package com.xiaohan.usercenter.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiaohan.usercenter.common.BaseResponse;
import com.xiaohan.usercenter.common.ResultUtils;
import com.xiaohan.usercenter.exception.CustomException;
import com.xiaohan.usercenter.model.domain.User;
import com.xiaohan.usercenter.model.domain.request.LoginRequest;
import com.xiaohan.usercenter.model.domain.request.RegisterRequest;
import com.xiaohan.usercenter.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

import static com.xiaohan.usercenter.common.ErrorCode.*;
import static com.xiaohan.usercenter.constant.UserConstant.ADMIN_ROLE;
import static com.xiaohan.usercenter.constant.UserConstant.USER_LOGIN_STATE;

/**
 * @program: backend
 * @description: 处理用户请求的控制层
 * @author: 韩小豪
 * @create: 2025-02-24 11:22
 **/

/**
 * 后端解决跨域问题
 * originPatterns后填写允许跨域的地址，默认为所有,最好显式设置
 * methods后填写允许跨域的请求方式
 * !!!allowCredentials需要显式设置为true，默认为false!!!否则还是跨域失败 -->  因为前端中设置了 credentials: 'include'
 */
@CrossOrigin(maxAge = 3600,originPatterns = {"http://175.178.59.14"},allowCredentials = "true")   //允许前端跨域请求后端接口（前端则可以不使用代理）  ---   在后端服务器层面解决跨域问题
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

	/**
	 * 后端项目启动测试接口
	 */
	@RequestMapping("/hello")
	public String hello() {
		return "backend start success!";
	}

	@Autowired
	private UserService userService;

	@PostMapping("/register")
	public BaseResponse<Long> register(@RequestBody RegisterRequest registerRequest) {   //@RequestBody注解使得MVC底层会自动将前端发送来的请求体映射到LoginRequest实体类中
		if (registerRequest == null) {
			throw new CustomException(PARAMS_ERROR,"请求参数为空");
		}
		String userAccount = registerRequest.getUserAccount();
		String password = registerRequest.getPassword();
		String checkPassword = registerRequest.getCheckPassword();
		if (StringUtils.isAnyBlank(userAccount, password, checkPassword)) {

			//使用封装好的错误状态码进行响应,而没有使用自定义异常或基于AOP的全局异常拦截
//			return ResultUtils.error(PARAMS_ERROR);

			//使用自定义异常中断程序
			throw new CustomException(PARAMS_ERROR,"输入内容含空");
		}

		Long result = userService.register(userAccount, password, checkPassword);
		return ResultUtils.success(result);
	}

	@PostMapping("/login")
	public BaseResponse<User> login(@RequestBody LoginRequest loginRequest, HttpServletRequest httpServletRequest) {   //@RequestBody注解使得MVC底层会自动将前端发送来的请求体映射到LoginRequest实体类中
		if (loginRequest == null) {
			throw new CustomException(PARAMS_ERROR,"请求参数为空");
		}
		//从请求参数对象中取值
		String userAccount = loginRequest.getUserAccount();
		String password = loginRequest.getPassword();
		if (StringUtils.isAnyBlank(userAccount, password)) {
			log.info("登陆失败，账号或密码为空!");
			throw new CustomException(PARAMS_ERROR,"输入内容含空");
		}

		User user = userService.login(userAccount, password, httpServletRequest);
		return ResultUtils.success(user);
	}

	//用户注销
	@PostMapping("/logout")
	public BaseResponse<Integer> logout(HttpServletRequest httpServletRequest) {   //@RequestBody注解使得MVC底层会自动将前端发送来的请求体映射到LoginRequest实体类中
		if (httpServletRequest == null) {
			throw new CustomException(SYSTEM_ERROR,"请求为空");
		}
		int result = userService.logout(httpServletRequest);
		return ResultUtils.success(result);
	}

	//删除用户
	@PostMapping(value = "/delete")
	public BaseResponse<Boolean> delete(@RequestBody long userId, HttpServletRequest httpServletRequest) {
		if (userId <= 0) {
			throw new CustomException(PARAMS_ERROR,"userId错误");
		}

		//鉴权：管理员才可以删除
		if (!isAdmin(httpServletRequest)) {   // isAdmin = false
			log.info("deleteFaild...Permission denied!");
			throw new CustomException(NO_AUTH,"无权限删除");
		}

		boolean result = userService.removeById(userId);//设置了Mybatis-plus的逻辑删除时，执行该方法后实际上是更新isDelete字段的值为1
		return ResultUtils.success(result);
	}

	//根据用户昵称查询满足条件的用户（模糊查询+去除已经被逻辑删除的用户）
	@GetMapping("/searchUsers")
	public BaseResponse<List<User>> searchUsers(String userName, HttpServletRequest httpServletRequest) {
		//鉴权，只有管理员可查
		if (!isAdmin(httpServletRequest)) {   // isAdmin = false
			log.info("selectFaild...Permission denied!");
			return null;
//			return new ArrayList<>();   //返回一个空集合，规范
//			return null;
		}

		//userName不为空时，执行模糊查询，返回符合条件的所有用户
		QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
		if (StringUtils.isNotBlank(userName)) {
			//注意列名区分大小写
			userQueryWrapper.like("userName", userName);
		}  //userName为空时，userQueryWrapper为空，默认查询所有

//		List<User> rsList = new ArrayList<>();
//		//遍历结果集合，并对所有用户的密码信息脱敏后以list集合的形式返回
//		for(User originUser : userService.list(userQueryWrapper)) {
//		    User safeUser = userService.getSafetyUser(originUser);
//			rsList.add(safeUser);
//		}
//		return rsList;

		List<User> users = userService.list(userQueryWrapper);  //被逻辑删除的不会查询
		//等效于
		List<User> safetyUsers = users.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());//Java 8 Stream API lambda表达式
		return ResultUtils.success(safetyUsers);
	}

	/**
	 * 获取当前登录的用户信息
	 * 注意：需要重新从数据库中获取最新的用户信息返回给前端
	 * 场景：当前用户的积分发生了变化，但是没有重新登录，因此从session中获取到的用户的积分还是会为之前的，不合理
	 *
	 * @param httpServletRequest 维护会话信息的请求对象
	 * @return
	 */
	@GetMapping("/getCurrent")
	private BaseResponse<User> getCurrentUser(HttpServletRequest httpServletRequest) {
		Object logingUser = httpServletRequest.getSession().getAttribute(USER_LOGIN_STATE);
		User user = (User) logingUser;
		if (user == null) {
			throw new CustomException(NOT_LOGIN,"请先登录");
		}

		//当前登录用户不为空，则根据该用户id从数据库中查询当前用户的最新信息返回给前端
		Long id = user.getId();
		User latestUser = userService.getById(id);

		// TODO 需要追加判断当前用户是否允许正常使用（有无被封号）
		User safetyUser = userService.getSafetyUser(latestUser);//返回脱敏后的用户
		return ResultUtils.success(safetyUser);
	}

	/**
	 * 判断当前用户的角色
	 *
	 * @param httpServletRequest 用以获取session
	 * @return true 表示当前用户为管理员
	 */
	private boolean isAdmin(HttpServletRequest httpServletRequest) {
		//获取session，随后获取当前登录的用户信息
		Object userObj = httpServletRequest.getSession().getAttribute(USER_LOGIN_STATE);  //json数据格式
		//类型转换为java中的user对象
		User user = (User) userObj;

//		if (user == null || user.getRole() != ADMIN_ROLE) {
//			return false;
//		}
//		return true;
		return user != null && user.getRole() == ADMIN_ROLE; //简写
	}
}
